// package com.jourwon.spring.boot.config.redis;
//
// import com.alibaba.fastjson.JSON;
// import io.lettuce.core.ClientOptions;
// import io.lettuce.core.ReadFrom;
// import io.lettuce.core.SocketOptions;
// import io.lettuce.core.cluster.ClusterClientOptions;
// import io.lettuce.core.cluster.ClusterTopologyRefreshOptions;
// import lombok.extern.slf4j.Slf4j;
// import org.apache.commons.lang3.StringUtils;
// import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
// import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
// import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
// import org.springframework.cache.annotation.CachingConfigurerSupport;
// import org.springframework.context.annotation.Bean;
// import org.springframework.context.annotation.Configuration;
// import org.springframework.data.redis.connection.RedisClusterConfiguration;
// import org.springframework.data.redis.connection.RedisConnectionFactory;
// import org.springframework.data.redis.connection.RedisNode;
// import org.springframework.data.redis.connection.RedisPassword;
// import org.springframework.data.redis.connection.RedisSentinelConfiguration;
// import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
// import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
// import org.springframework.data.redis.connection.lettuce.LettucePoolingClientConfiguration;
// import org.springframework.data.redis.core.HashOperations;
// import org.springframework.data.redis.core.ListOperations;
// import org.springframework.data.redis.core.RedisTemplate;
// import org.springframework.data.redis.core.SetOperations;
// import org.springframework.data.redis.core.ValueOperations;
// import org.springframework.data.redis.core.ZSetOperations;
// import org.springframework.data.redis.serializer.StringRedisSerializer;
// import org.springframework.util.Assert;
//
// import javax.annotation.Resource;
// import java.time.Duration;
// import java.util.ArrayList;
// import java.util.List;
// import java.util.Objects;
//
// /**
//  * Redis配置
//  *
//  * @author JourWon
//  * @date 2022/4/20
//  */
// @Slf4j
// @Configuration
// @ConditionalOnBean(value = {CustomRedisProperties.class})
// public class RedisConfig extends CachingConfigurerSupport {
//
//     @Resource
//     private CustomRedisProperties customRedisProperties;
//
//     /**
//      * lettuce连接池配置
//      *
//      * @return GenericObjectPoolConfig lettuce连接池配置
//      */
//     private GenericObjectPoolConfig genericObjectPoolConfig() {
//         GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig();
//
//         poolConfig.setMinIdle(customRedisProperties.getPool().getMinIdle());
//         poolConfig.setMaxIdle(customRedisProperties.getPool().getMaxIdle());
//         poolConfig.setMaxTotal(customRedisProperties.getPool().getMaxActive());
//         poolConfig.setMaxWaitMillis(customRedisProperties.getPool().getMaxWait().toMillis());
//         poolConfig.setTestWhileIdle(customRedisProperties.getPool().getTestWhileIdle());
//         poolConfig.setMinEvictableIdleTimeMillis(customRedisProperties.getPool().getMinEvictableIdleTimeMs());
//         poolConfig.setTimeBetweenEvictionRunsMillis(customRedisProperties.getPool().getTimeBetweenEvictionRunsMs());
//         poolConfig.setNumTestsPerEvictionRun(customRedisProperties.getPool().getNumTestsPerEvictionRun());
//
//         return poolConfig;
//     }
//
//     /**
//      * lettuce连接工厂
//      *
//      * @return RedisConnectionFactory lettuce连接工厂
//      */
//     @Bean
//     @ConditionalOnMissingBean(name = "redisConnectionFactory")
//     public RedisConnectionFactory redisConnectionFactory() {
//         if (CustomRedisProperties.RedisTypeEnum.STAND_ALONG.getValue().equals(customRedisProperties.getMode())) {
//             RedisStandaloneConfiguration configuration = new RedisStandaloneConfiguration();
//             Assert.notNull(customRedisProperties.getNodes(), "节点host:port配置不能为空");
//
//             String[] hostAndPort = customRedisProperties.getNodes().split(":");
//             Assert.isTrue(hostAndPort.length == 2, "Host and Port String needs to specified as host:port");
//             configuration.setHostName(hostAndPort[0]);
//             configuration.setPort(Integer.parseInt(hostAndPort[1]));
//             configuration.setPassword(RedisPassword.of(customRedisProperties.getPassword()));
//             configuration.setDatabase(customRedisProperties.getDatabase());
//
//             LettucePoolingClientConfiguration lettuceClientConfiguration = LettucePoolingClientConfiguration.builder()
//                     .poolConfig(genericObjectPoolConfig())
//                     .commandTimeout(Duration.ofMillis(customRedisProperties.getTimeout())).build();
//
//             LettuceConnectionFactory lettuceConnectionFactory = new LettuceConnectionFactory(configuration, lettuceClientConfiguration);
//             log.info("单节点Redis:{} ---初始化完成---", JSON.toJSONString(configuration));
//
//             return lettuceConnectionFactory;
//         } else if (CustomRedisProperties.RedisTypeEnum.CLUSTER.getValue().equals(customRedisProperties.getMode())) {
//             RedisClusterConfiguration configuration = new RedisClusterConfiguration();
//             Assert.notNull(customRedisProperties.getNodes(), "节点host:port配置不能为空");
//
//             configuration.setClusterNodes(readHostAndPortFromString(customRedisProperties.getNodes()));
//             if (StringUtils.isNotBlank(customRedisProperties.getPassword())) {
//                 configuration.setPassword(RedisPassword.of(customRedisProperties.getPassword()));
//             }
//             if (Objects.nonNull(customRedisProperties.getMaxRedirects())) {
//                 configuration.setMaxRedirects(customRedisProperties.getMaxRedirects());
//             }
//
//             LettuceConnectionFactory lettuceConnectionFactory = new LettuceConnectionFactory(configuration,
//                     lettuceClientConfiguration(genericObjectPoolConfig()));
//             log.info("集群Redis:{} ---初始化完成---", JSON.toJSONString(configuration));
//
//             return lettuceConnectionFactory;
//         } else if (CustomRedisProperties.RedisTypeEnum.SENTINEL.getValue().equals(customRedisProperties.getMode())) {
//             RedisSentinelConfiguration configuration = new RedisSentinelConfiguration();
//             Assert.notNull(customRedisProperties.getNodes(), "节点host:port配置不能为空");
//
//             configuration.setSentinels(readHostAndPortFromString(customRedisProperties.getNodes()));
//             configuration.setDatabase(customRedisProperties.getDatabase());
//             if (StringUtils.isNotBlank(customRedisProperties.getMaster())) {
//                 configuration.setMaster(customRedisProperties.getMaster());
//             }
//             if (StringUtils.isNotBlank(customRedisProperties.getPassword())) {
//                 configuration.setPassword(RedisPassword.of(customRedisProperties.getPassword()));
//             }
//
//             LettuceConnectionFactory lettuceConnectionFactory = new LettuceConnectionFactory(configuration, lettuceClientConfiguration(genericObjectPoolConfig()));
//             log.info("哨兵Redis:{} ---初始化完成---", JSON.toJSONString(configuration));
//
//             return lettuceConnectionFactory;
//         } else {
//             throw new RuntimeException("未知的Redis运行模式:0-单机;2-集群,当前配置:" + customRedisProperties.getMode());
//         }
//
//     }
//
//     /**
//      * lettuce客户端配置
//      *
//      * @param genericObjectPoolConfig lettuce连接池配置
//      * @return LettucePoolingClientConfiguration lettuce客户端配置
//      */
//     private LettucePoolingClientConfiguration lettuceClientConfiguration(GenericObjectPoolConfig genericObjectPoolConfig) {
//         // 配置用于开启自适应刷新和定时刷新。如自适应刷新不开启，Redis集群变更时将会导致连接异常
//         ClusterTopologyRefreshOptions clusterTopologyRefreshOptions = ClusterTopologyRefreshOptions.builder()
//                 // 开启周期刷新集群拓扑视图(默认60秒)
//                 .enablePeriodicRefresh(Duration.ofSeconds(60))
//                 // 开启所有自适应刷新，MOVED，ASK，PERSISTENT都会触发
//                 .enableAllAdaptiveRefreshTriggers()
//                 // 自适应刷新超时时间(默认30秒)
//                 .adaptiveRefreshTriggersTimeout(Duration.ofSeconds(30))
//                 .build();
//
//         ClusterClientOptions clusterClientOptions = ClusterClientOptions.builder()
//                 // 拓扑刷新
//                 .topologyRefreshOptions(clusterTopologyRefreshOptions)
//                 .disconnectedBehavior(ClientOptions.DisconnectedBehavior.REJECT_COMMANDS)
//                 // 默认就是true
//                 .autoReconnect(true)
//                 .socketOptions(
//                         SocketOptions.builder()
//                                 .keepAlive(true)
//                                 //默认10s
//                                 .connectTimeout(Duration.ofMillis(customRedisProperties.getConnectTimeout()))
//                                 .build()
//                 )
//                 // 取消校验集群节点的成员关系
//                 .validateClusterNodeMembership(false)
//                 .build();
//
//         LettucePoolingClientConfiguration lettuceClientConfiguration = LettucePoolingClientConfiguration.builder()
//                 .poolConfig(genericObjectPoolConfig)
//                 .commandTimeout(Duration.ofMillis(customRedisProperties.getTimeout()))
//                 .clientOptions(clusterClientOptions)
//                 .readFrom(ReadFrom.REPLICA_PREFERRED)
//                 .build();
//
//         return lettuceClientConfiguration;
//     }
//
//     /**
//      * 获取Redis节点列表
//      *
//      * @param hostAndPort hostAndPort
//      * @return List<RedisNode>
//      */
//     private List<RedisNode> readHostAndPortFromString(String hostAndPort) {
//         List<RedisNode> redisNodeList = new ArrayList<>();
//
//         String[] split = StringUtils.split(hostAndPort, ",");
//         for (String hostIp : split) {
//             String[] args = StringUtils.split(hostIp, ":");
//             Assert.isTrue(args.length == 2, "redis Host and Port String needs to specified as host:port");
//             redisNodeList.add(new RedisNode(args[0], Integer.valueOf(args[1])));
//         }
//
//         return redisNodeList;
//     }
//
//     /**
//      * RedisTemplate
//      *
//      * @param redisConnectionFactory lettuce连接工厂
//      * @return RedisTemplate
//      */
//     @Bean
//     @ConditionalOnMissingBean(name = "redisTemplate")
//     public RedisTemplate<String, String> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
//         RedisTemplate<String, String> template = new RedisTemplate<>();
//         template.setConnectionFactory(redisConnectionFactory);
//
//         StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
//         template.setKeySerializer(stringRedisSerializer);
//         template.setValueSerializer(stringRedisSerializer);
//
//         template.setHashKeySerializer(stringRedisSerializer);
//         template.setHashValueSerializer(stringRedisSerializer);
//         template.setDefaultSerializer(stringRedisSerializer);
//
//         template.afterPropertiesSet();
//         return template;
//     }
//
//     @Bean
//     public ValueOperations<String, String> valueOperations(RedisTemplate<String, String> redisTemplate) {
//         return redisTemplate.opsForValue();
//     }
//
//     @Bean
//     public HashOperations<String, String, String> hashOperations(RedisTemplate<String, String> redisTemplate) {
//         return redisTemplate.opsForHash();
//     }
//
//     @Bean
//     public ListOperations<String, String> listOperations(RedisTemplate<String, String> redisTemplate) {
//         return redisTemplate.opsForList();
//     }
//
//     @Bean
//     public SetOperations<String, String> setOperations(RedisTemplate<String, String> redisTemplate) {
//         return redisTemplate.opsForSet();
//     }
//
//     @Bean
//     public ZSetOperations<String, String> zSetOperations(RedisTemplate<String, String> redisTemplate) {
//         return redisTemplate.opsForZSet();
//     }
//
// }
